package com.think.teaching.controller;

import com.think.common.model.Result;
import com.think.common.model.ResultCode;
import com.think.common.utils.Common;
import com.think.common.utils.JSonUtil;
import com.think.common.utils.NetUtils;
import com.think.teaching.model.Class;
import com.think.teaching.model.College;
import com.think.teaching.model.Course;
import com.think.teaching.model.CourseUser;
import com.think.teaching.model.IlabLoginData;
import com.think.teaching.model.Major;
import com.think.teaching.model.School;
import com.think.teaching.model.StudentInfo;
import com.think.teaching.model.TeacherInfo;
import com.think.teaching.model.User;
import com.think.teaching.service.impl.ClassServiceImpl;
import com.think.teaching.service.impl.CollegeServiceImpl;
import com.think.teaching.service.impl.CourseServiceImpl;
import com.think.teaching.service.impl.CourseUserServiceImpl;
import com.think.teaching.service.impl.MajorServiceImpl;
import com.think.teaching.service.impl.SchoolServiceImpl;
import com.think.teaching.service.impl.StudentInfoServiceImpl;
import com.think.teaching.service.impl.TeacherInfoServiceImpl;
import com.think.teaching.service.impl.UserServiceImpl;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.collections4.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@RestController
@RequestMapping("v1")
@Api(tags = "用户接口")
@Slf4j
public class UserController {

	@Value("${user.server.url}")
	public String userServerUrl;
	@Autowired
	private StudentInfoServiceImpl studentService;
	@Autowired
	private TeacherInfoServiceImpl teacherService;
	@Autowired
	private CourseUserServiceImpl courseUserServiceImpl;
	@Autowired
	private ClassServiceImpl classServiceImpl;
	@Autowired
	private MajorServiceImpl majorServiceImpl;
	@Autowired
	private CollegeServiceImpl collegeServiceImpl;
	@Autowired
	private SchoolServiceImpl schoolServiceImpl;
	@Autowired
	private UserServiceImpl userServiceImpl;
	@Autowired
	private CourseServiceImpl courseServiceImpl;

	@Value("${platform.client}")
	private String client;
	@Value("${platform.secret}")
	private String secret;

	@PostMapping("open/login")
	public Result UserLogin(@RequestBody() IlabLoginData data) {
		String parameter = String.format("client_id=%s&client_secret=%s&grant_type=password&username=%s&password=%s",
				client, secret, data.getUsername(), data.getPassword());
		try {
			String json = NetUtils.doPost(userServerUrl + "/oauth/token", parameter, null);
  			Map<String, Object> res = JSonUtil.fromJson(json, Map.class);

			if (res.containsKey("access_token")) {
				return Result.success(res);
			}
			return Result.failure(ResultCode.USER_NAME_PASSWORD_INVALID);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.println("exp:------------" + e.getMessage());
			return Result.failure(ResultCode.USER_NAME_PASSWORD_INVALID, e.getMessage());
		}
	}

	@Autowired
	RedisTemplate redisTemplate;

	@GetMapping("/open/ilabLogin/{id}")
	public Result CheckIlabLogin(@PathVariable Integer id) {
		ValueOperations valueOperations = redisTemplate.opsForValue();
		Course course = courseServiceImpl.getById(id);
		if (course == null) {
			return Result.failure(ResultCode.COURSE_NOT_EXIST);
		}
		/* 从redis中获取 */
		String key = Common.GetCurrentAuthor().getUserId() + "_" + course.getIlabAppId() + "_access_token";
		System.out.println(key);
		String accessToken = (String) valueOperations.get(key);
		if (accessToken == null || accessToken.isEmpty()) {
			return Result.failure(ResultCode.ILAB_LOGIN_NOT_MATCH);
		} else {
			return Result.success(accessToken);
		}
	}

	@RequestMapping(value = "/open/ilabLogin", method = RequestMethod.POST)
	public String ilabLogin(@RequestBody() IlabLoginData data, HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		Course course = courseServiceImpl.getById(data.getCourse());
		if (course == null) {
			return JSonUtil.toJson(Result.failure(ResultCode.COURSE_NOT_EXIST));

		}
		String parameter = String.format(
				"client_id=%s&client_secret=%s&grant_type=ilab&username=%s&password=%s&appid=%s&appsecret=%s", client,
				secret, data.getUsername(), data.getPassword(), course.getIlabAppId().toString(),
				course.getIlabAppSecret());

		try {
			Map<String, Object> result = JSonUtil
					.getJsonObj(NetUtils.doPost(userServerUrl + "/oauth/token", parameter, null));
			if (result != null && result.containsKey("payload") &&result.get("payload")!= null ) {

				ValueOperations valueOperations = redisTemplate.opsForValue();
				/* 从redis中获取 */
				String key = result.get("userId") + "_" + course.getIlabAppId() + "_access_token";
				valueOperations.set(key, result.get("payload").toString());
				redisTemplate.expire(key, 24, TimeUnit.HOURS);
			}
			return NetUtils.doPost(userServerUrl + "/oauth/token", parameter, null);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return JSonUtil.toJson(Result.failure(ResultCode.SYSTEM_INNER_ERROR, e.getMessage()));
		}
	}
	
	
	@RequestMapping(value = "/open/ticketLogin", method = RequestMethod.POST)
	@ApiOperation(value = "用户ilabTicket", notes = "实验空间提供的ticket登录")
//	@ApiImplicitParams(value = {
//			@ApiImplicitParam(name="ticket",value="验证凭证",required=true,dataType="String"),
//		    @ApiImplicitParam(name="course",value="课程",required=true,dataType="String"),
//
//	})
	public String ilabLogin(@RequestBody()Map<String, Object> data, HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		if (!data.containsKey("course") || !data.containsKey("ticket")) {
			return  JSonUtil.toJson(Result.failure(ResultCode.PARAM_NOT_COMPLETE));
		}
		Integer courseId = (Integer)data.get("course");
		Course course = courseServiceImpl.getById(courseId);
		if (course == null) {
			return JSonUtil.toJson(Result.failure(ResultCode.COURSE_NOT_EXIST));

		}
		String parameter = String.format(
				"client_id=%s&client_secret=%s&grant_type=ilab_token&token=%s&appid=%s&appsecret=%s", client,
				secret, data.get("ticket"), course.getIlabAppId().toString(),
				URLEncoder.encode(course.getIlabAppSecret()));

		try {
			Map<String, Object> result = JSonUtil
					.getJsonObj(NetUtils.doPost(userServerUrl + "/oauth/token", parameter, null));
			if (result != null && result.containsKey("payload") &&result.get("payload")!= null ) {

				ValueOperations valueOperations = redisTemplate.opsForValue();
				/* 从redis中获取 */
				String key = result.get("userId") + "_" + course.getIlabAppId() + "_access_token";
				valueOperations.set(key, result.get("payload").toString());
				redisTemplate.expire(key, 24, TimeUnit.HOURS);
			}
			String reString = NetUtils.doPost(userServerUrl + "/oauth/token", parameter, null);
			Map<String, Object> res = JSonUtil.fromJson(reString, Map.class);
			if (res.containsKey("access_token")) {
				return JSonUtil.toJson(Result.success(res));
			}
			else {
				return reString;
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return JSonUtil.toJson(Result.failure(ResultCode.SYSTEM_INNER_ERROR, e.getMessage()));
		}
	}

	@PostMapping("user/bindTeacher")
	public Result UserBindTeacher(@RequestBody() TeacherInfo data) {
		if (teacherService.GetTeacherByUserId(Common.GetCurrentAuthor().getUserId()) != null) {
			return Result.failure(ResultCode.TEACHER_ALREADY_EXIST);

		} else {
			data.setUserId(Common.GetCurrentAuthor().getUserId());
			data.setState(2);
			TeacherInfo res = teacherService.AddNewTeacher(data);
			if (res != null) {
				return Result.success(res);
			} else {
				return Result.failure(ResultCode.SYSTEM_DATABASE_ERROR);
			}
		}
	}

	@PostMapping("admin/bindTeacher/refuse/{id}")
	public Result RefuseUserBindTeacher(@PathVariable("id") Integer id) {
		if (teacherService.getById(id) == null) {
			return Result.failure(ResultCode.TEACHER_NOT_EXIST);
		}
		if (teacherService.removeById(id)) {
			return Result.success();
		} else {
			return Result.failure(ResultCode.SYSTEM_DATABASE_ERROR);
		}
	}

	@PostMapping("admin/bindTeacher/accept/{id}")
	public Result AcceptUserBindTeacher(@PathVariable("id") Integer id) {
		TeacherInfo data = teacherService.getById(id);

		if (data == null) {
			return Result.failure(ResultCode.TEACHER_NOT_EXIST);
		}
		data.setState(1);
		if (teacherService.updateById(data)) {
			return Result.success();
		} else {
			return Result.failure(ResultCode.SYSTEM_DATABASE_ERROR);
		}
	}

	@PostMapping("user/bindStudent")
	public Result UserBindStudent(@RequestBody() StudentInfo data) {
		if (studentService.GetStudentInfoByUserId(Common.GetCurrentAuthor().getUserId()) != null) {
			return Result.failure(ResultCode.STUDENT_ALREADY_EXIST);
		} else {
			data.setUserId(Common.GetCurrentAuthor().getUserId());
			data.setState(2);
			StudentInfo res = studentService.AddStudentInfo(data);
			if (res != null) {
				return Result.success(res);
			} else {
				return Result.failure(ResultCode.SYSTEM_DATABASE_ERROR);
			}
		}
	}

	@PostMapping("admin/bindStudent/refuse/{id}")
	public Result RefuseUserBindStudent(@PathVariable("id") Integer id) {
		if (studentService.getById(id) == null) {
			return Result.failure(ResultCode.STUDENT_NOT_EXIST);
		}
		if (studentService.removeById(id)) {
			return Result.success();
		} else {
			return Result.failure(ResultCode.SYSTEM_DATABASE_ERROR);
		}
	}

	@PostMapping("admin/bindStudent/accept/{id}")
	public Result AcceptUserBindStudent(@PathVariable("id") Integer id) {
		StudentInfo data = studentService.getById(id);

		if (data == null) {
			return Result.failure(ResultCode.STUDENT_NOT_EXIST);
		}
		data.setState(1);
		if (studentService.updateById(data)) {
			return Result.success();
		} else {
			return Result.failure(ResultCode.SYSTEM_DATABASE_ERROR);
		}
	}

	@GetMapping("user/checkBind")
	public Result CheckBindStatus() {
		StudentInfo studentInfo = studentService.GetStudentInfoByUserId(Common.GetCurrentAuthor().getUserId());
		if (studentInfo != null) {
			Map<String, Object> result = new HashedMap<String, Object>();
			result.put("truename", studentInfo.getTrueName());
			result.put("studentId", studentInfo.getStudentId());
			result.put("state", studentInfo.getState());
			System.out.println(studentInfo.getClassId());
			Class class1 = classServiceImpl.getById(studentInfo.getClassId());
			Major major = majorServiceImpl.getById(class1.getMajor());
			College college = collegeServiceImpl.getById(major.getCollege());
			result.put("class", new HashedMap<String, Object>() {
				{
					put("id", class1.getId());
					put("name", class1.getClassIndex());
				}
			});
			result.put("major", new HashedMap<String, Object>() {
				{
					put("id", major.getId());
					put("name", major.getMajorName());
				}
			});
			result.put("college", new HashedMap<String, Object>() {
				{
					put("id", college.getId());
					put("name", college.getCollegeName());
				}
			});
			return Result.success(result);// (ResultCode.STUDENT_ALREADY_EXIST);
		}
		TeacherInfo teacherInfo = teacherService.GetTeacherByUserId(Common.GetCurrentAuthor().getUserId());
		if (teacherInfo != null) {
			return Result.success(teacherInfo);
		}
		return Result.failure(ResultCode.RESULT_DATA_NONE);
	}

	@ApiOperation("获取当前用户已经加入课程")
	@GetMapping("user/course/{page}/{count}")
	public Result GetSelectedCourse(@PathVariable("page") Integer page, @PathVariable("count") Integer count,
			@RequestParam(required = false, defaultValue = "0") Integer mode,
			@RequestParam(required = false, defaultValue = "0") Integer type,
			@RequestParam(required = false, defaultValue = "0") Integer tag) {
		return Result.success(courseServiceImpl.GetUserSelectedCourseWithFilter(Common.GetCurrentAuthor().getUserId(),
				count, page, type, mode, tag));// (ResultCode.STUDENT_ALREADY_EXIST);
	}

	@ApiOperation("当前用户加入课程")
	@PostMapping("user/course/{id}")
	public Result UserSelectCourse(@PathVariable("id") Integer id) {
		if (courseServiceImpl.getById(id) == null) {
			return Result.failure(ResultCode.COURSE_NOT_EXIST);
		}
		if (courseUserServiceImpl.GetByUserIDAndCourseId(id, Common.GetCurrentAuthor().getUserId()) != null) {
			return Result.failure(ResultCode.COURSE_USER_EXIST);
		} else {
			CourseUser data = new CourseUser();
			data.setStudentId(Common.GetCurrentAuthor().getUserId());
			data.setCourseId(id);

			return Result.success(courseUserServiceImpl.AddCourseUser(data));// (ResultCode.COURSE_USER_NOT_EXIST);
		}
	}

	@ApiOperation("判断当前用户是否加入课程")
	@GetMapping("user/course/{id}")
	public Result CheckUserSelectCourse(@PathVariable("id") Integer id) {
		if (courseUserServiceImpl.GetByUserIDAndCourseId(id, Common.GetCurrentAuthor().getUserId()) == null) {
			return Result.failure(ResultCode.COURSE_USER_NOT_EXIST);
		} else {
			return Result.success();// (ResultCode.COURSE_USER_NOT_EXIST);
		}
	}

	@PostMapping("user/updateTeacher")
	public Result UpdateUserBindTeacher(@RequestBody() TeacherInfo data) {
		TeacherInfo info = teacherService.GetTeacherByUserId(Common.GetCurrentAuthor().getUserId());
		if (info == null) {
			return Result.failure(ResultCode.TEACHER_ALREADY_EXIST);

		} else {
			if (teacherService.UpdateTeacher(data) != null) {
				return Result.success(data);
			} else {
				return Result.failure(ResultCode.SYSTEM_DATABASE_ERROR);
			}
		}
	}

	@PostMapping("user/updateStudent")
	public Result UpdateUserBindStudent(@RequestBody() StudentInfo data) {
		StudentInfo info = studentService.GetStudentInfoByUserId(Common.GetCurrentAuthor().getUserId());
		if (info == null) {
			return Result.failure(ResultCode.TEACHER_ALREADY_EXIST);

		} else {
			if (studentService.UpdateStudentInfo(data) != null) {
				return Result.success(data);
			} else {
				return Result.failure(ResultCode.SYSTEM_DATABASE_ERROR);
			}
		}
	}

	@ApiOperation("获取用户信息")
	@GetMapping("user/info")
	public Result GetUserInfo() {
		User user = userServiceImpl.getById(Common.GetCurrentAuthor().getUserId());
		if (user == null) {

			Map<String, Object> res = JSonUtil.fromJson(NetUtils.doGet(userServerUrl + "/v1/user/info?access_token=" + getCurrentToken()), Map.class);
			Map<String, Object> data = (Map<String, Object>) res.get("data");
			user = userServiceImpl.CheckAndInitUser((Integer) data.get("id"), (String) data.get("nickname"),
					(String) data.get("name"), (String) data.get("avatarUrl"), (String) data.get("email"));
		}

		StudentInfo studentInfo = studentService.GetStudentInfoByUserId(Common.GetCurrentAuthor().getUserId());
		if (studentInfo != null) {
			Map<String, Object> result = new HashedMap<String, Object>();
			result.put("truename", studentInfo.getTrueName());
			result.put("studentId", studentInfo.getStudentId());
			result.put("state", studentInfo.getState());
			Class class1 = classServiceImpl.getById(studentInfo.getClassId());
			if (class1 == null) {
				user.setAdditionalData(result);
				return Result.success(user);
			}
			result.put("grade", class1.getGrade());
			result.put("class", new HashedMap<String, Object>() {
				{
					put("id", class1.getId());
					put("name", class1.getClassIndex());
				}
			});
			Major major = majorServiceImpl.getById(class1.getMajor());
			if (major == null) {
				user.setAdditionalData(result);
				return Result.success(user);
			}
			result.put("major", new HashedMap<String, Object>() {
				{
					put("id", major.getId());
					put("name", major.getMajorName());
				}
			});
			College college = collegeServiceImpl.getById(major.getCollege());
			if (college == null) {
				user.setAdditionalData(result);
				return Result.success(user);
			}
			result.put("college", new HashedMap<String, Object>() {
				{
					put("id", college.getId());
					put("name", college.getCollegeName());
				}
			});
			School school = schoolServiceImpl.getById(college.getSchool());
			if (school == null) {
				user.setAdditionalData(result);
				return Result.success(user);
			}
			result.put("school", new HashedMap() {
				{
					put("id", school.getId());
					put("name", school.getName());
				}
			});
			user.setAdditionalData(result);
		}
		TeacherInfo teacherInfo = teacherService.GetTeacherByUserId(Common.GetCurrentAuthor().getUserId());
		if (teacherInfo != null) {
			user.setAdditionalData(teacherInfo);
		}
		return Result.success(user);

	}

	@ApiOperation("更新用户信息")
	@PostMapping("user/info")
	public Result UpdateUserInfo(@RequestBody User data) {
		User user = userServiceImpl.getById(Common.GetCurrentAuthor().getUserId());
		if (user == null) {
			return Result.failure(ResultCode.USER_NOT_EXIST);
		} else {
			if (data.getAvatarUrl() != null) {
				user.setAvatarUrl(data.getAvatarUrl());
			}
			if (data.getNickname() != null) {
				user.setNickname(data.getNickname());
			}
			if (data.getGender() != null) {
				user.setGender(data.getGender());
			}
			if (data.getBirthday() != null) {
				user.setBirthday(data.getBirthday());
			}
			return Result.success(userServiceImpl.updateById(user));

		}
	}
	

	public static String getCurrentToken() {
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
				.getRequest();
		String token = request.getHeader("access_token");
		if (token == null || token.length() == 0) {
			token = request.getHeader("Authorization");
		}
		if (token == null || token.length() == 0) {
			token = request.getParameter("access_token");
		}
		log.error(token);
		System.out.println(token);
		if (token != null && token.startsWith("Bearer ")) {
			token = token.substring(7);
		}
		return token;
	}
}
